local lfs = require "lfs"
local nl=require "luaNumeric"

-- 科学计数
--无法解析 .1之类的数据
number_pattern = "[ ]*[+-]?%d+[.]?%d*[Ee+-]*%d*";


----------------------------------------------------------------------------------------------------------
--获取文件父目录
function strippath(filename)
	return string.match(filename,"(.+)/[^/]*%.%w+$") -- *nix system
	--return string.match(filename, ��(.+)\\[^\\]*%.%w+$��)  -- windows
end
----------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------
--文件是否存在，并且能能否读取
function file_exists(name)
   local f=io.open(name,"r")
   if f~=nil then io.close(f) return true else return false end
end
----------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------
--获取文件名(含扩展名)
function stripfilename(filename)
	return string.match(filename, ".+/([^/]*%.%w+)$") -- *nix system
	--return string.match(filename, ��.+\\([^\\]*%.%w+)$��) �� *windows system
end
----------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------
--获取文件名(不含扩展名)
function getFilenameWithoutExt(filename)
	return string.match(filename, ".+/([^/]*)%.%w+$") -- *nix system
	--return string.match(filename, ��.+\\([^\\]*%.%w+)$��) �� *windows system
end
----------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------
--获取文件名(不含扩展名,包含目录名)
function getFilename(filename)
	local idx = filename:match(".+()%.%w+$") -- *nix system
	if idx~=nil then
		return filename:sub(1, idx-1)
	else
		return filename
	end
end
----------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------
--获取文件扩展名
function stripextension(filename)
	return filename:match(".+%.(%w+)$")
end
----------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------
function string.split(s, delimiter)
	result = {};
	for match in (s..delimiter):gmatch("%s*(.-)%s*"..delimiter.."+") do
	    table.insert(result, match);
	end
	return result;
end
----------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------
function print_table_table( tbl )
     for k,v in pairs (tbl) do
	  print("key:"..k..", vals:")
          local str;
	  for kk,vv in pairs( v ) do 
		str = (str or "    ")..kk..":"..vv..","
	  end
	  print( str )
     end
end
----------------------------------------------------------------------------------------------------------

function print_table( tbl )
    local str;
    for kk,vv in pairs( tbl ) do 
	str = (str or "")..kk..":"..vv..","
    end
    print( str )
end


----------------------------------------------------------------------------------------------------------
function table2number( tbl )
     for k,v in pairs (tbl) do
--~ 	  print( #self, k, v, tonumber(v) )
	  tbl[k] = tonumber(v)
     end
      return tbl;
end
----------------------------------------------------------------------------------------------------------


----------------------------------------------------------------------------------------------------------
function file2table( path, delimiter )
	if delimiter==nil then delimiter = "\t" end;
	local table_data={};
	local file = io.open( path,"r");
	-- if file==nil then return; end
	assert( file, "file:"..path.." open fail!");
	for line in file:lines() do
--~ 	     print( line )
	    vals = string.split( line, delimiter ) 
	     vals = table2number( vals )
--~ 	     print_table_val( vals );
	     table.insert(table_data, vals)
        end
	file:close()    
	-- print( "read line:", #table_data );
	-- print_table_table( table_data );
	return table_data;
end
----------------------------------------------------------------------------------------------------------


----------------------------------------------------------------------------------------------------------
function file2StrTable( path, delimiter )
	if delimiter==nil then delimiter = "\t" end;
	local table_data={};
	local file = io.open( path,"r");
	-- if file==nil then return; end
	assert( file, "file:"..path.." open fail!");
	for line in file:lines() do
--~ 	     print( line )
	    vals = string.split( line, delimiter ) 
	     -- vals = table2number( vals )
--~ 	     print_table_val( vals );
	     table.insert(table_data, vals)
        end
	file:close()    
	-- print( "read line:", #table_data );
	-- print_table_table( table_data );
	return table_data;
end
----------------------------------------------------------------------------------------------------------


----------------------------------------------------------------------------------------------------------
function table2file( data, path, delimiter )
	if delimiter==nil then delimiter = "\t" end;
	local file = io.open( path,"w");
	-- if file==nil then return; end
	assert( file, "file:"..path.." open fail!");
	for k,v in pairs(data) do
	      for k1,v1 in pairs(v) do
		     file:write( v1, delimiter)
	      end
	      file:write("\n")
	end
	file:close()   
end
----------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------
function clone(org)
    local function copy(org, res)
        for k,v in pairs(org) do
            if type(v) ~= "table" then
                res[k] = v;
            else
                res[k] = {};
                copy(v, res[k])
            end
        end
    end
 
    local res = {}
    copy(org, res)
    return res
end
----------------------------------------------------------------------------------------------------------


function dump_value_(v)
    if type(v) == "string" then
        --v = "\"" .. v .. "\""
        v = "" .. v .. ""
    end
    return tostring(v)
end

function dump_vvalue_(v,nest)
    local mm = '';
    for k=1,nest do mm = mm..'=';end
    if type(v) == "string" then
        --v = "\"" .. v .. "\""
        v = '['..mm..'[' .. v .. ']'..mm..']'
    end
    return tostring(v)
end
 
function split_d(input, delimiter)
    input = tostring(input)
    delimiter = tostring(delimiter)
    if (delimiter == "") then return false end
    local pos, arr = 0, {}
    for st, sp in function() return string.find(input, delimiter, pos, true) end do
        table.insert(arr, string.sub(input, pos, st - 1))
        pos = sp + 1
    end
    table.insert(arr, string.sub(input, pos))
    return arr
end
 
function trim_d(input)
    return (string.gsub(input, "^%s*(.-)%s*$", "%1"))
end
 
--[[
打印table的工具函数
@params value 需要打印的内容
@params desciption 描述
@params nesting 打印内容的嵌套级数，默认4级
]]
function dump_t(value, desciption, nesting)
    if type(nesting) ~= "number" then nesting = 4 end
 
    local lookupTable = {}
    local result = {}
 
    local traceback = split_d(debug.traceback("", 2), "\n")
    -- print("dump from: " .. trim(traceback[3]))
 
    local function dump_(value, desciption, indent, nest, keylen)
        desciption = desciption or ""
        local spc = ""
        if type(keylen) == "number" then
            spc = string.rep(" ", keylen - string.len(dump_value_(desciption)))
	    --desciption = '';
	    --print(desciption,keylen)
        end
        if type(value) ~= "table" then
            result[#result +1 ] = string.format("%s%s%s  %s;", indent, dump_value_(desciption), spc, dump_vvalue_(value,nest))
        elseif lookupTable[tostring(value)] then
            result[#result +1 ] = string.format("%s%s%s  *REF*;", indent, dump_value_(desciption), spc)
        else
            lookupTable[tostring(value)] = true
            if nest > nesting then
                result[#result +1 ] = string.format("%s%s  *MAX NESTING*;", indent, dump_value_(desciption))
            else
                result[#result +1 ] = string.format("%s%s  {", indent, dump_value_(desciption))
                local indent2 = indent.."    "
                local keys = {}
                local keylen = 0
                local values = {}
                for k, v in pairs(value) do
                    keys[#keys + 1] = k
                    local vk = dump_value_(k)
                    local vkl = string.len(vk)
                    if vkl > keylen then keylen = vkl end
                    values[k] = v
                end
                table.sort(keys, function(a, b)
                    if type(a) == "number" and type(b) == "number" then
                        return a < b
                    else
                        return tostring(a) < tostring(b)
                    end
                end)
                for i, k in ipairs(keys) do
		    if type(k) == 'number' then 
			dump_(values[k], '', indent2, nest + 1, keylen)
		    else
		    	dump_(values[k], k..' = ', indent2, nest + 1, keylen)
		    end
                end
                result[#result +1] = string.format("%s};", indent)
            end
        end
    end
    dump_(value, desciption, ' ', 1)
 
    str = '';
    for i, line in ipairs(result) do
        str = str .. line ..'\n';
    end
    return str;
end


function undump_t(str)
	local f = assert(load(' return ' .. str ..''))
	return f();
end